#pragma once
#include <BasisObj.h>
#include <D3DX10.h>
#include <string>
#include <w32lib_basic.h>
#include <vector>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <boost/unordered_map.hpp>
#include <Effect.h>
#include <Material.h>

namespace grflib
{
    namespace engine
    {
        namespace aux
        {
            class CStaticMesh : public grflib::engine::core::IRenderable
            {
            public:
                CStaticMesh(void);
                virtual ~CStaticMesh(void);

                virtual HRESULT OnCreateDevice(ID3D10Device *pd3dDevice,
                    const DXGI_SURFACE_DESC *pBufferSurfaceDesc);
                virtual void OnDestroy(void);

                virtual grflib::engine::core::BBox<float> &GetBoundingBox(void);

                //Call UpdateGPUBuffers ONLY IF buffer size doesn't change!
                void UpdateGPUBuffers(ID3D10Device *pd3dDevice);

                void SetEffectTechnique(const std::string &effectName, const std::string &techName)
                { m_effectName = effectName; m_techniqueName = techName; }

                void Expose(std::size_t **ppNGrp,
                            std::vector< boost::shared_ptr<std::vector<float>> > **ppVertexVec,
                            std::vector< boost::shared_ptr<std::vector<DWORD>> > **ppIndexVec,
                            std::vector<D3D10_PRIMITIVE_TOPOLOGY> **ppTopology,
                            std::vector< boost::shared_ptr<std::vector<D3D10_INPUT_ELEMENT_DESC>> > **ppLayoutVec,
                            std::vector<std::size_t> **ppStrideVec,
                            boost::unordered_map<UINT, std::string> **ppMaterialMap);

                const std::vector< boost::shared_ptr<std::vector<float>> > &GetVertexVec(void);
                const std::vector< boost::shared_ptr<std::vector<DWORD>> > &GetIndexVec(void);
                const std::vector< boost::shared_ptr<std::vector<D3D10_INPUT_ELEMENT_DESC>> > &GetVertexLayoutVec(void);

            protected:
                virtual HRESULT PreRender(ID3D10Device *pd3dDevice,
                    const D3DXMATRIX *pWorldMat,
                    double fTime,
                    float fElapsedTime,
                    UINT pass);
                virtual HRESULT Render(ID3D10Device *pd3dDevice,
                    const D3DXMATRIX *pWorldMat,
                    double fTime,
                    float fElapsedTime,
                    UINT pass);

            protected:
                HRESULT CreateVertexBuffer(ID3D10Device *pd3dDevice);
                void DestroyVertexBuffer(void);

            protected:
                std::size_t m_nGroups;
                std::vector< boost::shared_ptr<std::vector<float>> > m_vertexVec; //only 32bit float pos|normal|texcoord are supported
                std::vector< boost::shared_ptr<std::vector<DWORD>> > m_indexVec;
                std::vector<ID3D10Buffer *> m_vertexBufferPtrs;
                std::vector<ID3D10Buffer *> m_indexBufferPtrs;
                std::vector<D3D10_PRIMITIVE_TOPOLOGY> m_primitiveTopology;

                std::vector< boost::shared_ptr<std::vector<D3D10_INPUT_ELEMENT_DESC>> > m_vertexLayouts;
                std::vector<std::size_t> m_vertexStride;

                engine::core::BBox<float> m_bbox;

                //all groups must share the same effect and technique
                std::string m_effectName;
                std::string m_techniqueName;
                boost::unordered_map<UINT, std::string /*material name*/> m_materials;

            protected:
                //pass among PreRender, Render and PostRender
                D3D10_TECHNIQUE_DESC m_techDesc;
                ID3D10EffectTechnique *m_pTech;
                boost::weak_ptr<grflib::engine::core::CEffect> m_pEffect;
            };

        } //namespace aux
    } //namespace engine
} //namespace grflib